﻿using System;
using System.Net.Sockets;
using Jiubang.Communication.Common;
using Jiubang.Communication.Server.SessionControl;
using Jiubang.Util;
using log4net;

namespace Jiubang.Communication.Server.RequestRouter {
    /// <summary>
    /// 请求分派器
    /// </summary>
    public class RequestDispatcher<T> where T : class, IMessageSender,IMessageListener {
        private readonly IRequestHandler[] _handlers = new IRequestHandler[byte.MaxValue];
        protected ILog Log { get; private set; }
        private readonly RequestProtocol _protocol = RequestProtocol.Instance;

        /// <summary>
        /// </summary>
        public RequestDispatcher(T server) {
            if (server == null)
                throw new ArgumentNullException("server");

            Log = LogManager.GetLogger(GetType());
            Server = server;
            server.MessageReceived += (sender, args) => Accept(args);
        }

        /// <summary>
        /// 通讯框架服务端。程序通过该接口向客户端发送数据。
        /// </summary>
        protected T Server { get; private set; }

        /// <summary>
        /// 通知框架服务端接收到客户端消息时将调用该方法。<br/>
        /// 方法体内部替换Buffer之必须使用BufferManager的FreeBuffer方法进行缓冲区回收，否则将造成缓冲区变小直至不可用<br/>
        /// </summary>
        /// <param name="args"></param>
        public virtual bool Accept(SocketAsyncEventArgs args) {
            byte handlerId = args.Buffer[args.Offset];
            var handler = _handlers[handlerId];
            if (handler == null) {
                Log.Warn("RequestHandler[" + handlerId + "]未注册。消息内容为:" + args.Buffer.Concat(","));
                return false;
            }
            return handler.Accept(new RequestContext(args,Server));
        }

        /// <summary>
        /// 注册一个IRequestHandler用于处理消息
        /// </summary>
        /// <param name="unRegisteredHandler">待注册的实例</param>
        /// <exception cref="Exception">具有相同HandlerID的实例重复注册</exception>
        public void RegisterHandler(IRequestHandler unRegisteredHandler) {
            byte registerId = unRegisteredHandler.HandlerId;

            IRequestHandler handler = _handlers[registerId];
            if (handler != null)
                throw new Exception("ID=[" + registerId + "]被" + unRegisteredHandler.GetType().FullName + "重复注册");
            _handlers[registerId] = unRegisteredHandler;
        }
    }
}